package org.example.demo.apiv2.sql;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import org.example.demo.apiv2.constant.ExpressionType;
import org.example.demo.apiv2.constant.ExpressionValueType;
import org.example.demo.apiv2.entity.ExpressionEntity;
import org.example.demo.apiv2.entity.FieldEntity;

import java.util.List;

@Slf4j
public class ExpressionParser {

    public static String getExpressionString(ExpressionEntity expressionEntity) {
        String expressionType = expressionEntity.getExpressionType();
        Object value = expressionEntity.getValue();

        switch (expressionType) {
            case ExpressionType.LEFT_PARENTHESIS:
            case ExpressionType.RIGHT_PARENTHESIS:
            case ExpressionType.AND:
            case ExpressionType.OR:
                return value.toString();
            case ExpressionType.CONDITION:
                return getConditionExpression(expressionEntity).toString();
            default:
                log.error("不支持的表达式类型: {}", expressionType);
                throw new IllegalArgumentException("不支持的表达式类型: " + expressionType);
        }
    }

    public static Expression getConditionExpression(ExpressionEntity expressionEntity) {
        FieldEntity fieldEntity = expressionEntity.getField();
        String operator = expressionEntity.getOperator();
        String valueType = expressionEntity.getValueType();
        Object value = expressionEntity.getValue();

        Expression expression = null;
        if (StrUtil.isNotEmpty(operator)){
            expression = OperatorParser.getExpressionByOperator(operator);
        }
        if (expressionEntity.getField() != null){
            Column leftExpression = FieldParser.getColumn(expressionEntity.getField());
            OperatorParser.setLeftExpression(expression, leftExpression);

        }
        switch (valueType) {
            case ExpressionValueType.CONSTANT:
                Expression rightExpression1 = ExpressionValueUtil.getConstantValue(value, fieldEntity.getColDataType());
                OperatorParser.setRightExpression(expression, rightExpression1);
                break;
            case ExpressionValueType.VARIABLE:
                Expression rightExpression2 = ExpressionValueUtil.getVariableValue(value);
                OperatorParser.setRightExpression(expression, rightExpression2);
                break;
            case ExpressionValueType.FIELD:
                Expression rightExpression3 = ExpressionValueUtil.getFieldValue(value);
                OperatorParser.setRightExpression(expression, rightExpression3);
                break;
            case ExpressionValueType.SQL_STRING:
                Expression rightExpression4 = ExpressionValueUtil.getSqlStringValue(value);
                Parenthesis parenthesis = new Parenthesis(rightExpression4);
                OperatorParser.setRightExpression(expression, parenthesis);
                break;
            case ExpressionValueType.EXPRESSION_STRING:
                expression = ExpressionValueUtil.getExpressionStringValue(value);
                break;
        }
        return expression;

    }


    public static Expression getFilterExpression(List<ExpressionEntity> expressionEntityList) {
        if (CollectionUtil.isEmpty(expressionEntityList)){
            return null;
        }

        StringBuilder expressionStringBuilder = new StringBuilder();
        for (ExpressionEntity expressionEntity : expressionEntityList) {
            expressionStringBuilder.append(getExpressionString(expressionEntity)).append(" ");
        }
        Expression expression;
        try {
            expression = CCJSqlParserUtil.parseCondExpression(expressionStringBuilder.toString());
            return expression;
        } catch (JSQLParserException e) {
            throw new RuntimeException(e);
        }
    }
}
